////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Microsoft Corporation.  All rights reserved.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Gadgeteer.Interfaces
{
    using System;
    using Microsoft.SPOT;
    using Microsoft.SPOT.Hardware;
    using Gadgeteer.Modules;

    /// <summary>
    /// Represents pulse width modulation (PWM) output using a single socket pin.
    /// </summary>
    public class PWMOutput
    {
        private Socket.SocketInterfaces.PWM pwm;
        private Socket.Pin pin;

        // Note: A constructor summary is auto-generated by the doc builder.
        /// <summary>
        /// </summary>
        /// <remarks>This automatically checks that the socket supports Type P, and reserves the pin.
        /// An exception will be thrown if there is a problem with these checks.</remarks>
        /// <param name="socket">The socket that supports pulse width modulation (PWM) output.</param>
        /// <param name="pin">The pin on the socket that supports PWM.</param>
        /// <param name="module">The module using this PWM output interface, which can be null if unspecified.</param>
        public PWMOutput(Socket socket, Socket.Pin pin, Module module)
        {
            this.pin = pin;
            socket.EnsureTypeIsSupported('P',module);

            switch(pin) 
            {
                case Socket.Pin.Seven: 
                    pwm = socket.PWM7;
                    break;
                case Socket.Pin.Eight:
                    pwm = socket.PWM8;
                    break;
                case Socket.Pin.Nine:
                    pwm = socket.PWM9;
                    break;
                default:
                    if (module != null)
                    {
                        throw new Socket.InvalidSocketException("Module " + module + " cannot use PWM interface on pin " + pin + " - pin must be in range 7 to 9.");
                    }
                    else
                    {
                        throw new Socket.InvalidSocketException("Cannot use PWM interface on pin " + pin + " - pin must be in range 7 to 9.");
                    }
            }

            if (pwm == null)
            {
                // this is a mainboard error that should not happen (we already check for it in SocketInterfaces.RegisterSocket) but just in case...
                throw new Socket.InvalidSocketException("Socket " + socket + " has an error with its PWM functionality. Please try a different socket.");
            }

            socket.ReservePin(pin, module);
            this.pwm.Active = false;
        }

        /// <summary>
        /// Sets the frequency and duty cycle of the <see cref="PWMOutput"/> interface.
        /// </summary>
        /// <param name="frequency">Required frequency in Hertz.</param>
        /// <param name="dutyCycle">Duty cycle percentage: 0 to 100 inclusive.</param>
        public void Set(int frequency, byte dutyCycle)
        {
            this.pwm.Set(frequency, dutyCycle);
        }

        /// <summary>
        /// Sets the pulse width modulation (PWM) using the period time and high time. 
        /// </summary>
        /// <param name="period_ns">Period of the signal in nanoseconds.</param>
        /// <param name="highTime_ns">High time of the signal in nanoseconds.</param>
        public void SetPulse(uint period_ns, uint highTime_ns)
        {
            this.pwm.SetPulse(period_ns, highTime_ns);
        }

        /// <summary>
        /// Gets or sets a Boolean value that indicates whether the PWM interface is active, <b>true</b> if active
        /// otherwise <b>false</b>.
        /// </summary>
        public bool Active
        {
            get
            {
                return pwm.Active;
            }
            set
            {
                pwm.Active = value;
            }
        }
    }

}
